home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectDraw / AnimatePalette / animatepalette.cpp next >
C/C++ Source or Header  |  2001-10-31  |  18KB  |  550 lines

  1. //-----------------------------------------------------------------------------
  2. // File: AnimatePalette.cpp
  3. //
  4. // Desc: This sample demonstrates how to do DirectDraw palette animatation
  5. //       when in full-screen mode.
  6. //
  7. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <ddraw.h>
  12. #include <mmsystem.h>
  13. #include <dxerr8.h>
  14. #include "resource.h"
  15. #include "ddutil.h"
  16.  
  17.  
  18.  
  19.  
  20. //-----------------------------------------------------------------------------
  21. // Defines, constants, and global variables
  22. //-----------------------------------------------------------------------------
  23. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  24. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  25.  
  26. #define SCREEN_WIDTH    640
  27. #define SCREEN_HEIGHT   480
  28. #define SCREEN_BPP      8
  29.  
  30. #define SPRITE_DIAMETER 48
  31. #define NUM_SPRITES     25
  32.  
  33. #define HELPTEXT TEXT("Press Escape to quit.")
  34.  
  35. struct SPRITE_STRUCT
  36. {
  37.     FLOAT                fPosX; 
  38.     FLOAT                fPosY;
  39.     FLOAT                fVelX; 
  40.     FLOAT                fVelY;
  41. };
  42.  
  43. CDisplay*            g_pDisplay        = NULL;
  44. CSurface*            g_pLogoSurface    = NULL;  
  45. CSurface*            g_pTextSurface    = NULL;  
  46. LPDIRECTDRAWPALETTE  g_pDDPal          = NULL; 
  47. PALETTEENTRY         g_pe[256];
  48. HWND                 g_hWnd            = NULL;
  49. BOOL                 g_bActive         = FALSE; 
  50. DWORD                g_dwLastTick;
  51. SPRITE_STRUCT        g_Sprite[NUM_SPRITES]; 
  52.  
  53.  
  54.  
  55.  
  56. //-----------------------------------------------------------------------------
  57. // Function-prototypes
  58. //-----------------------------------------------------------------------------
  59. LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  60. HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel );
  61. HRESULT InitDirectDraw( HWND hWnd );
  62. VOID    FreeDirectDraw();
  63. HRESULT ProcessNextFrame();
  64. VOID    UpdateSprite( SPRITE_STRUCT* pSprite, FLOAT fTimeDelta );
  65. HRESULT CyclePalette();
  66. HRESULT DisplayFrame();
  67. HRESULT RestoreSurfaces();
  68.  
  69.  
  70.  
  71.  
  72. //-----------------------------------------------------------------------------
  73. // Name: WinMain()
  74. // Desc: Entry point to the program. Initializes everything and calls
  75. //       UpdateFrame() when idle from the message pump.
  76. //-----------------------------------------------------------------------------
  77. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
  78. {
  79.     MSG         msg;
  80.     HACCEL   hAccel;
  81.     HRESULT  hr;
  82.  
  83.     if( FAILED( WinInit( hInst, nCmdShow, &g_hWnd, &hAccel ) ) )
  84.         return FALSE;
  85.  
  86.     if( FAILED( hr = InitDirectDraw( g_hWnd ) ) )
  87.     {
  88.         DXTRACE_ERR( TEXT("InitDirectDraw"), hr );
  89.         MessageBox( g_hWnd, TEXT("DirectDraw init failed. ")
  90.                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  91.                     MB_ICONERROR | MB_OK );
  92.         return FALSE;
  93.     }
  94.  
  95.     // Display the sprites on the screen
  96.     DisplayFrame();
  97.   
  98.     while( TRUE )
  99.     {
  100.         // Look for messages, if none are found then 
  101.         // update the state and display it
  102.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  103.         {
  104.             if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
  105.             {
  106.                 // WM_QUIT was posted, so exit
  107.                 return (int)msg.wParam;
  108.             }
  109.  
  110.             // Translate and dispatch the message
  111.             if( 0 == TranslateAccelerator( g_hWnd, hAccel, &msg ) )
  112.             {
  113.                 TranslateMessage( &msg ); 
  114.                 DispatchMessage( &msg );
  115.             }
  116.         }
  117.         else
  118.         {
  119.             if( g_bActive )
  120.             {
  121.                 // Display the bitmap to the screen
  122.                 if( FAILED( hr = ProcessNextFrame() ) )
  123.                 {
  124.                     SAFE_DELETE( g_pDisplay );
  125.                            
  126.                     if( hr == E_NOTIMPL )
  127.                     {
  128.                         MessageBox( NULL, TEXT("The driver does not support waiting for vertical blank. ")
  129.                                     TEXT("This is expected if the HW acceleration is disabled. ")
  130.                                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  131.                                     MB_ICONERROR | MB_OK );
  132.                     }
  133.                     else
  134.                     {                                                                          
  135.                         DXTRACE_ERR( TEXT("ProcessNextFrame"), hr );
  136.                         MessageBox( g_hWnd, TEXT("Displaying the next frame failed. ")
  137.                                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  138.                                     MB_ICONERROR | MB_OK );
  139.                     }
  140.                     
  141.                     return FALSE;
  142.                 }
  143.             }
  144.             else
  145.             {
  146.                 // Make sure we go to sleep if we have nothing else to do
  147.                 WaitMessage();
  148.             }
  149.         }
  150.     }
  151. }
  152.  
  153.  
  154.  
  155.  
  156. //-----------------------------------------------------------------------------
  157. // Name: WinInit()
  158. // Desc: Init the window
  159. //-----------------------------------------------------------------------------
  160. HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel )
  161. {
  162.     WNDCLASS wc;
  163.     HWND     hWnd;
  164.     HACCEL   hAccel;
  165.  
  166.     // Register the Window Class
  167.     wc.lpszClassName = TEXT("AnimatePalette");
  168.     wc.lpfnWndProc   = MainWndProc;
  169.     wc.style         = CS_VREDRAW | CS_HREDRAW;
  170.     wc.hInstance     = hInst;
  171.     wc.hIcon         = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
  172.     wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
  173.     wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  174.     wc.lpszMenuName  = NULL;
  175.     wc.cbClsExtra    = 0;
  176.     wc.cbWndExtra    = 0;
  177.  
  178.     if( RegisterClass( &wc ) == 0 )
  179.         return E_FAIL;
  180.  
  181.     // Load keyboard accelerators
  182.     hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  183.  
  184.     // Create and show the main window
  185.     hWnd = CreateWindowEx( 0, TEXT("AnimatePalette"), TEXT("DirectDraw AnimatePalette Sample"),
  186.                            WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
  187.                              CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL );
  188.     if( hWnd == NULL )
  189.         return E_FAIL;
  190.  
  191.     ShowWindow( hWnd, nCmdShow );
  192.     UpdateWindow( hWnd );
  193.  
  194.     *phWnd   = hWnd;
  195.     *phAccel = hAccel;
  196.  
  197.     return S_OK;
  198. }
  199.  
  200.  
  201.  
  202.  
  203. //-----------------------------------------------------------------------------
  204. // Name: InitDirectDraw()
  205. // Desc: Create the DirectDraw object, and init the surfaces
  206. //-----------------------------------------------------------------------------
  207. HRESULT InitDirectDraw( HWND hWnd )
  208. {
  209.     HRESULT             hr;
  210.     int                 iSprite;
  211.  
  212.     g_pDisplay = new CDisplay();
  213.     if( FAILED( hr = g_pDisplay->CreateFullScreenDisplay( hWnd, SCREEN_WIDTH, 
  214.                                                           SCREEN_HEIGHT, SCREEN_BPP ) ) )
  215.     {        
  216.         MessageBox( hWnd, TEXT("This display card does not support 640x480x8. "),
  217.                     TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );
  218.         return DXTRACE_ERR( TEXT("CreateFullScreenDisplay"), hr );
  219.     }
  220.  
  221.     // Create and set the palette when in palettized color
  222.     if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &g_pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )
  223.         return DXTRACE_ERR( TEXT("CreatePaletteFromBitmap"), hr );
  224.  
  225.     if( FAILED( hr = g_pDisplay->SetPalette( g_pDDPal ) ) )
  226.         return DXTRACE_ERR( TEXT("SetPalette"), hr );
  227.  
  228.     // Store the palette entires in a global data structure 
  229.     // so we can animate the palette
  230.     if( FAILED( hr = g_pDDPal->GetEntries(0, 0, 256, g_pe ) ) )
  231.         return DXTRACE_ERR( TEXT("GetEntries"), hr );
  232.  
  233.     // Create a surface, and draw a bitmap resource on it.  
  234.     if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap( &g_pLogoSurface, MAKEINTRESOURCE( IDB_DIRECTX ), 
  235.                                                           SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )
  236.         return DXTRACE_ERR( TEXT("CreateSurfaceFromBitmap"), hr );
  237.  
  238.     // Create a surface, and draw text to it.  
  239.     if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, HELPTEXT, 
  240.                                                         RGB(0,0,0), RGB(255, 255, 0) ) ) )
  241.         return DXTRACE_ERR( TEXT("CreateSurfaceFromText"), hr );
  242.  
  243.     // Set the color key for the logo sprite to black
  244.     if( FAILED( hr = g_pLogoSurface->SetColorKey( 0 ) ) )
  245.         return DXTRACE_ERR( TEXT("SetColorKey"), hr );
  246.  
  247.     // Init all the sprites.  All of these sprites look the same, 
  248.     // using the g_pDDSLogo surface. 
  249.     for( iSprite = 0; iSprite < NUM_SPRITES; iSprite++ )
  250.     {
  251.         // Set the sprite's position and velocity
  252.         g_Sprite[iSprite].fPosX = (float) (rand() % SCREEN_WIDTH);
  253.         g_Sprite[iSprite].fPosY = (float) (rand() % SCREEN_HEIGHT); 
  254.  
  255.         g_Sprite[iSprite].fVelX = 500.0f * rand() / RAND_MAX - 250.0f;
  256.         g_Sprite[iSprite].fVelY = 500.0f * rand() / RAND_MAX - 250.0f;
  257.     }
  258.  
  259.     return S_OK;
  260. }
  261.  
  262.  
  263.  
  264.  
  265. //-----------------------------------------------------------------------------
  266. // Name: FreeDirectDraw()
  267. // Desc: Release all the DirectDraw objects
  268. //-----------------------------------------------------------------------------
  269. VOID FreeDirectDraw()
  270. {
  271.     SAFE_DELETE( g_pLogoSurface );
  272.     SAFE_DELETE( g_pTextSurface );
  273.     SAFE_DELETE( g_pDisplay );
  274. }
  275.  
  276.  
  277.  
  278.  
  279.  
  280. //-----------------------------------------------------------------------------
  281. // Name: MainWndProc()
  282. // Desc: The main window procedure
  283. //-----------------------------------------------------------------------------
  284. LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  285. {
  286.     switch (msg)
  287.     {
  288.         case WM_COMMAND:
  289.             switch( LOWORD(wParam) )
  290.             {
  291.                 case IDM_EXIT:
  292.                     // Received key/menu command to exit app
  293.                     PostMessage( hWnd, WM_CLOSE, 0, 0 );
  294.                     return 0L;
  295.             }
  296.             break; // Continue with default processing
  297.  
  298.         case WM_SETCURSOR:
  299.             // Hide the cursor in fullscreen 
  300.             SetCursor( NULL );
  301.             return TRUE;
  302.  
  303.         case WM_SIZE:
  304.             // Check to see if we are losing our window...
  305.             if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
  306.                 g_bActive = FALSE;
  307.             else
  308.                 g_bActive = TRUE;
  309.             break;
  310.  
  311.         case WM_SYSCOMMAND:
  312.             // Prevent moving/sizing and power loss in fullscreen mode
  313.             switch( wParam )
  314.             {
  315.                 case SC_MOVE:
  316.                 case SC_SIZE:
  317.                 case SC_MAXIMIZE:
  318.                 case SC_MONITORPOWER:
  319.                     return TRUE;
  320.             }
  321.             break;
  322.  
  323.         case WM_EXITMENULOOP:
  324.             // Ignore time spent in menu
  325.             g_dwLastTick = timeGetTime();
  326.             break;
  327.  
  328.         case WM_EXITSIZEMOVE:
  329.             // Ignore time spent resizing
  330.             g_dwLastTick = timeGetTime();
  331.             break;
  332.  
  333.         case WM_DESTROY:
  334.             // Cleanup and close the app
  335.             FreeDirectDraw();
  336.             PostQuitMessage( 0 );
  337.             return 0L;
  338.     }
  339.  
  340.     return DefWindowProc(hWnd, msg, wParam, lParam);
  341. }
  342.  
  343.  
  344.  
  345.  
  346. //-----------------------------------------------------------------------------
  347. // Name: ProcessNextFrame()
  348. // Desc: Move the sprites, blt them to the back buffer, then 
  349. //       flips the back buffer to the primary buffer
  350. //-----------------------------------------------------------------------------
  351. HRESULT ProcessNextFrame()
  352. {
  353.     HRESULT hr;
  354.  
  355.     // Figure how much time has passed since the last time
  356.     DWORD dwCurrTick = timeGetTime();
  357.     DWORD dwTickDiff = dwCurrTick - g_dwLastTick;
  358.  
  359.     // Don't update if no time has passed 
  360.     if( dwTickDiff == 0 )
  361.         return S_OK; 
  362.  
  363.     g_dwLastTick = dwCurrTick;
  364.  
  365.     // Move the sprites according to how much time has passed
  366.     for( int iSprite = 0; iSprite < NUM_SPRITES; iSprite++ )
  367.         UpdateSprite( &g_Sprite[ iSprite ], dwTickDiff / 1000.0f );
  368.  
  369.     // Cycle the palette every frame
  370.     if( FAILED( hr = CyclePalette() ) )
  371.         return DXTRACE_ERR( TEXT("CyclePalette"), hr );
  372.  
  373.     // Display the sprites on the screen
  374.     if( FAILED( hr = DisplayFrame() ) )
  375.     {
  376.         if( hr != DDERR_SURFACELOST )
  377.         {
  378.             FreeDirectDraw();
  379.             return DXTRACE_ERR( TEXT("DisplayFrame"), hr );
  380.         }
  381.  
  382.         // The surfaces were lost so restore them 
  383.         RestoreSurfaces();
  384.     }
  385.  
  386.     return S_OK;
  387. }
  388.  
  389.  
  390.  
  391.  
  392. //-----------------------------------------------------------------------------
  393. // Name: CyclePalette()
  394. // Desc: Cycle the palette colors 2 through 37 - this is
  395. //       will change the color for 'X' in the sprite.
  396. //-----------------------------------------------------------------------------
  397. HRESULT CyclePalette()
  398. {
  399.     HRESULT hr;
  400.  
  401.     for( int i = 2; i < 37; i++ )
  402.     {
  403.         // This just does something interesting but simple by shifting each 
  404.         // color component independently 
  405.         g_pe[ i ].peBlue  += 8;       
  406.         g_pe[ i ].peRed   += 4;
  407.         g_pe[ i ].peGreen += 2;
  408.     }
  409.  
  410.     // Wait until the screen is synchronzied at a vertical-blank interval.
  411.     // This may return E_NOTIMPL if the ddraw is not hardware accelerated
  412.     hr = g_pDisplay->GetDirectDraw()->WaitForVerticalBlank( DDWAITVB_BLOCKBEGIN, NULL );
  413.     if( FAILED( hr ) )
  414.     {
  415.         FreeDirectDraw();
  416.         return DXTRACE_ERR( TEXT("WaitForVerticalBlank"), hr );
  417.     }
  418.  
  419.     // Now that we are synchronzied at a vertical-blank 
  420.     // interval, update the palette 
  421.     if( FAILED( hr = g_pDDPal->SetEntries( 0, 0, 256, g_pe ) ) )
  422.     {
  423.         FreeDirectDraw();
  424.         return DXTRACE_ERR( TEXT("SetEntries"), hr );
  425.     }
  426.  
  427.     return S_OK;
  428. }
  429.  
  430.  
  431.  
  432.  
  433. //-----------------------------------------------------------------------------
  434. // Name: UpdateSprite()
  435. // Desc: Move the sprite around and make it bounce based on how much time 
  436. //       has passed
  437. //-----------------------------------------------------------------------------
  438. VOID UpdateSprite( SPRITE_STRUCT* pSprite, FLOAT fTimeDelta )
  439. {    
  440.     // Update the sprite position
  441.     pSprite->fPosX += pSprite->fVelX * fTimeDelta;
  442.     pSprite->fPosY += pSprite->fVelY * fTimeDelta;
  443.  
  444.     // Clip the position, and bounce if it hits the edge
  445.     if( pSprite->fPosX < 0.0f )
  446.     {
  447.         pSprite->fPosX  = 0;
  448.         pSprite->fVelX = -pSprite->fVelX;
  449.     }
  450.  
  451.     if( pSprite->fPosX >= SCREEN_WIDTH - SPRITE_DIAMETER )
  452.     {
  453.         pSprite->fPosX = SCREEN_WIDTH - 1 - SPRITE_DIAMETER;
  454.         pSprite->fVelX = -pSprite->fVelX;
  455.     }
  456.  
  457.     if( pSprite->fPosY < 0 )
  458.     {
  459.         pSprite->fPosY = 0;
  460.         pSprite->fVelY = -pSprite->fVelY;
  461.     }
  462.  
  463.     if( pSprite->fPosY > SCREEN_HEIGHT - SPRITE_DIAMETER )
  464.     {
  465.         pSprite->fPosY = SCREEN_HEIGHT - 1 - SPRITE_DIAMETER;
  466.         pSprite->fVelY = -pSprite->fVelY;
  467.     }   
  468. }
  469.  
  470.  
  471.  
  472.  
  473. //-----------------------------------------------------------------------------
  474. // Name: DisplayFrame()
  475. // Desc: Blts a the sprites to the back buffer, then flips the 
  476. //       back buffer onto the primary buffer.
  477. //-----------------------------------------------------------------------------
  478. HRESULT DisplayFrame()
  479. {
  480.     HRESULT hr;
  481.  
  482.     if( NULL == g_pDisplay )
  483.         return S_OK;
  484.  
  485.     // Fill the back buffer with black, ignoring errors until the flip
  486.     g_pDisplay->Clear( 0 );
  487.  
  488.     // Blt the help text on the backbuffer, ignoring errors until the flip
  489.     g_pDisplay->Blt( 10, 10, g_pTextSurface, NULL );
  490.  
  491.     // Blt all the sprites onto the back buffer using color keying,
  492.     // ignoring errors until the flip. Note that all of these sprites 
  493.     // use the same DirectDraw surface.
  494.     for( int iSprite = 0; iSprite < NUM_SPRITES; iSprite++ )
  495.     {
  496.         g_pDisplay->Blt( (DWORD)g_Sprite[iSprite].fPosX, 
  497.                          (DWORD)g_Sprite[iSprite].fPosY, 
  498.                          g_pLogoSurface, NULL );
  499.     }
  500.  
  501.     // We are in fullscreen mode, so perform a flip and return 
  502.     // any errors like DDERR_SURFACELOST
  503.     if( FAILED( hr = g_pDisplay->Present() ) )
  504.     {
  505.         return hr;
  506.     }
  507.  
  508.     return S_OK;
  509. }
  510.  
  511.  
  512.  
  513.  
  514. //-----------------------------------------------------------------------------
  515. // Name: RestoreSurfaces()
  516. // Desc: Restore all the surfaces, and redraw the sprite surfaces.
  517. //-----------------------------------------------------------------------------
  518. HRESULT RestoreSurfaces()
  519. {
  520.     HRESULT hr;
  521.  
  522.     if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) )
  523.         return DXTRACE_ERR( TEXT("RestoreAllSurfaces"), hr );
  524.  
  525.     // No need to re-create the surface, just re-draw it.
  526.     if( FAILED( hr = g_pTextSurface->DrawText( NULL, HELPTEXT, 
  527.                                                0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )
  528.         return DXTRACE_ERR( TEXT("DrawText"), hr );
  529.  
  530.     // We need to release and re-load, and set the palette again to 
  531.     // redraw the bitmap on the surface.  Otherwise, GDI will not 
  532.     // draw the bitmap on the surface with the right palette
  533.     SAFE_RELEASE( g_pDDPal );
  534.  
  535.     if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &g_pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )
  536.         return DXTRACE_ERR( TEXT("CreatePaletteFromBitmap"), hr );
  537.  
  538.     if( FAILED( hr = g_pDisplay->SetPalette( g_pDDPal ) ) )
  539.         return DXTRACE_ERR( TEXT("SetPalette"), hr );
  540.  
  541.     // No need to re-create the surface, just re-draw it.
  542.     if( FAILED( hr = g_pLogoSurface->DrawBitmap( MAKEINTRESOURCE( IDB_DIRECTX ),
  543.                                                  SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )
  544.         return DXTRACE_ERR( TEXT("DrawBitmap"), hr );
  545.  
  546.     return S_OK;
  547. }
  548.  
  549.  
  550.